package com.g.ocache.impl.store.entry;

import com.g.ocache.StoreEntry;

/**
 * 
 * @author zhangyf
 * @param <K>
 * @param <V>
 */
public class TtlStoreEntry<K, V> implements StoreEntry<K, V> {
	//
	private K key;
	private V value;
	protected int timeToLive;
	protected long creationTime;

	/**
	 * 
	 * @param key
	 * @param value
	 */
	public TtlStoreEntry(K key, V value) {
		this.key = key;
		this.value = value;
	}
	
	/**
	 * 
	 */
	public K getKey() {
		return key;
	}

	public V getValue() {
		return value;
	}

	public boolean isExpired() {
		//
		if (timeToLive <= 0) {
			return false;
		}

		//
		long expirationTime = creationTime + timeToLive * 1000L;
		long now = System.currentTimeMillis();
		return now > expirationTime;
	}
	
	/**
	 * 
	 */
	public int getTimeToLive() {
		return timeToLive;
	}

	public void setTimeToLive(int timeToLive) {
		this.timeToLive = timeToLive;
	}
	
	public long getCreationTime() {
		return creationTime;
	}
	
	public void setCreationTime(long creationTime) {
		this.creationTime = creationTime;
	}
	
	/**
	 * 
	 */
	public interface CreationTimeAware<V> {
		long getCreationTime(V value);
	}
	
	public static class FactoryImpl<K, V> implements Factory<K, V> {
		//
		private int timeToLive;
		private CreationTimeAware<V> creationTimeAware;

		/**
		 * 
		 */
		public FactoryImpl(int timeToLive) {
			this(timeToLive, null);
		}
		
		public FactoryImpl(int timeToLive, CreationTimeAware<V> creationTimeAware) {
			this.timeToLive = timeToLive;
			this.creationTimeAware = creationTimeAware;
		}

		/**
		 * 
		 */
		public StoreEntry<K, V> create(K key, V value) {
			//
			TtlStoreEntry<K, V> storeEntry = new TtlStoreEntry<K, V>(key, value);
			storeEntry.setTimeToLive(timeToLive);
			
			//
			if (creationTimeAware == null) {
				storeEntry.setCreationTime(System.currentTimeMillis());
			} else {
				storeEntry.setCreationTime(creationTimeAware.getCreationTime(value));
			}
			return storeEntry;
		}
	}
}
